package net.sk.china.common.utils;

import io.jsonwebtoken.*;
import net.sk.china.common.exception.TalkException;

import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;

/**
 * JWT 工具类
 * +----------------------------------------------------------------------
 * | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * +----------------------------------------------------------------------
 * | Copyright (c) 2018-2024 聊来All rights reserved.
 * +----------------------------------------------------------------------
 * | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * +----------------------------------------------------------------------
 * | @Author: 聊来 <18970881148@qq.com>
 * +----------------------------------------------------------------------
 * | DateTime: 2024/6/2 11:54
 * +----------------------------------------------------------------------
 */
public class JwtUtil {

    /**
     * 实例
     */
    private static JwtUtil instance;

    /**
     * 发行者
     */
    private static final String SUB_OBJECT = "聊来";

    /**
     * 过期时间，默认7天
     */
    private static final long EXPIRED = 1000 * 60 * 60 * 24 * 7;

    /**
     * jwt构造
     */
    private static JwtBuilder jwtBuilder;

    private static final String APP_SECRET = "-MkCvW6grsYI1FlQ";

    /**
     * 公钥
     */
    private static final String RSA_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjerfkdZ4IY1yaDbvNvmAQizZxIUxTEPqJP2gl9u5KRWJo69U+Mdw1ttSwYTbXJdTU9VWMLGrY6u7knhYyTXyXmwk90xuq+UvruavwQOqlobXG4BN8UHUGObiKbecVx2WxWToycWxK2Yxix53gMMaosTQ8xo+4pZzcDh2x7wqqUcXjXnm4ez0OQmYQd+p/NDNq1C2P/1GsntWRAM3g46Z1JLye7i85UvdixUKkgeI2UYGbq7V2okHqzy8+unXyvaHmwW21K4iu8k5fFXA2yd9ssAbr6+vMe7kpFhNXH2hXBePcPrm1CCvEMOZPHdcDsJg0gj0+ipe+7MLlAmQObB8mwIDAQAB";

    /**
     * 私钥
     */
    private static final String RSA_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCN6t+R1nghjXJoNu82+YBCLNnEhTFMQ+ok/aCX27kpFYmjr1T4x3DW21LBhNtcl1NT1VYwsatjq7uSeFjJNfJebCT3TG6r5S+u5q/BA6qWhtcbgE3xQdQY5uIpt5xXHZbFZOjJxbErZjGLHneAwxqixNDzGj7ilnNwOHbHvCqpRxeNeebh7PQ5CZhB36n80M2rULY//Uaye1ZEAzeDjpnUkvJ7uLzlS92LFQqSB4jZRgZurtXaiQerPLz66dfK9oebBbbUriK7yTl8VcDbJ32ywBuvr68x7uSkWE1cfaFcF49w+ubUIK8Qw5k8d1wOwmDSCPT6Kl77swuUCZA5sHybAgMBAAECggEAc0qA7+BU3aUkcWdXdMjCmoAHNbCiuPtfZ0eoRFYbGTZHB/PzStvzXoj0tQPylUjWR//DMnHT83fbPQWJ04SA7pZafZDZQ8o/r4328A3Dct/+NnhIWZuJ6+T9jLh+SQNfreLpfqmc4c32p7dLjA50QBE2UphayAdDpsIoNOE3oyZEJIGtGjie7mWUfaKOUfDdhjmgI4DwPWANOKPsAJhT2IVSb9PLzvWawmOrY3lQsi8i2po48twX4TzIrZXfr2GnJqcaCre6wPN7tsLhgzgrbQe+eDoyHiNTFB9IPOQRRvxPKjLh1UQdlBvL7GzjHeoMuuIp3XcDZk3pj6auA+so+QKBgQDk55SOQATGqiMO7WcNuzwAUOKBoKqmaUR67VVGLNyKiT8GCN4518drHQyF3i/ODcAqmGTjK0NkLf/dx/pZyYmdWQ8TQGvsvcH8QtSinSeAfdU2um71+p4p075vb6RRU91rHcmvAI/crV3apEQCXX7qBp06loBjmQUIiPjnFfcYJQKBgQCet1nZV5h6sD5p9tfdDjo69p+V1iCu68hG4g/+7KufxBGgbGs9S3h8ODdpA/cZLhWwoXbYcL/KYdT6k2b7ikJVtTQNaArZs+5MzDBmQ/4ez6YL3zaMJCgn87lfxe3H5gq7KN+8bf/ttAp1VDskXUBug9b9E+dyizjWpmqD9W3FvwKBgQCYsjsRIXeOJxS38noaWNpPw6U1n732wKYj8oo+A9MivydBmUzU/TJUK86cxnjRVa7pOzuhpsyP2XejtLE2kBCy3CQITaMxC+yJoPNDft5JAqfmmDtI72PutweEQs80SWOc/wP5L8DIDwZawdV0VnZBGyRrXtZKmlsXNHgFf0uT2QKBgHA30QYzwfKVJDwFtJBuW8uOzjzBvjAPM3aypX6n1ZzLo27a2WPoNZMWqE7O5+ncxKczMnVMGr68NzrH95tIISi6Sshj1LAiYQ3ZnSrhTg544L0qIEYr1lyRHXNS3ZFl3BaCitaOq9JkZrSYToyihkjdXKdpaE57kz9pQIx2fhu/AoGBAOLhpkVq9B2Q5Tzcf6bpd+8H4j77sjYxfN+Nx2uqJAaVjiu0+78v0fwF0AfBfYx1QiytFYSgCw9qWXBGeQ1Y7xM0fj0FEE7J4nKGcgTNrw3WspEFOMELOyYwn5RIRU4EZgn2xeHdaBEg5xkS8U6QCMCgyFEcr9bkDx3GzO8dVSIv";

    /**
     * 获取实例
     * @return {@code JwtUtil}
     */
    public static JwtUtil getInstance(){
        if (instance == null){
            instance = new JwtUtil();
        }
        jwtBuilder = Jwts.builder();
        return instance;
    }


    /**
     * 生成 TOKEN （对称）
     * JwtUtil jwt = JwtUtil.getInstance();
     *         String token = jwt
     *                 .claim("id",1)
     *                 .generateToken();
     *         System.out.println(token);
     * @param data 附属信息（其他元数据）
     * @return {@code String}
     */
    public String createToken(String data) {
        return jwtBuilder
                // 发行者
                .setSubject(SUB_OBJECT)
                // 发行时间
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRED))
                .claim("data", data)
                // 签名类型 与 密钥
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compressWith(CompressionCodecs.DEFLATE)
                .compact();
    }

    /**
     * 解析 TOKEN （对称）
     * @param token 令牌
     * @return {@code Claims}
     */
    public Claims checkToken(String token){
        return Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token).getBody();
    }

    /**
     * 生成 TOKEN （非对称）
     * @param data 附属信息（其他元数据）
     * @return {@code String}
     */
    public String createTokenRsa(String data) {
        try {
//            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//            keyPairGenerator.initialize(2048);
//            KeyPair keyPair = keyPairGenerator.generateKeyPair();
//            PrivateKey privateKey = keyPair.getPrivate();
//            PublicKey publicKey = keyPair.getPublic();
//            String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
//            String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
//
//            System.out.println("私钥：" + privateKeyString);
//            System.out.println("公钥：" + publicKeyString);

            byte[] privateKeyBytes = Base64.getDecoder().decode(RSA_PRIVATE_KEY);
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);

            return  jwtBuilder.setSubject(SUB_OBJECT).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRED)).claim("data", data).signWith(SignatureAlgorithm.RS256, privateKey).compact();
        } catch (Exception e) {
            throw new TalkException("TOKEN生成异常：" + e.getMessage());
        }

    }

    /**
     * 解析 TOKEN （非对称）
     * @param token 令牌
     * @return {@code Claims}
     */
    public Claims checkTokenRsa(String token) {
        try {
            byte[] publicKeyBytes = Base64.getDecoder().decode(RSA_PUBLIC_KEY);
            X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
            RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

            return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            throw new TalkException("TOKEN异常：" + e.getMessage());
        }
    }
}